package yawning.mew.bear;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import yawning.mew.ProcEffect;
import yawning.mew.Report;
import yawning.mew.util.CSVDumper;

public class BearThreatReport extends Report {
	public enum BearThreatStat implements IStat {
		TOTAL_DAMAGE,
		TOTAL_DAMAGE_TAKEN,
		TOTAL_DAMAGE_BASE,

		DEMORALIZING_ROAR_UPTIME,
		INFECTED_WOUNDS_UPTIME,
		SAVAGE_DEFENSE_UPTIME,
		SAVAGE_DEFENSE_ABSORBED,
		SAVAGE_DEFENSE_AVG_SZ,
		SAVAGE_DEFENSE_PROCS,
		SAVAGE_DEFENSE_PROC_INTERVAL,

		BARKSKIN_UPTIME,
		TIER_12_4PC_UPTIME,
		SURVIVAL_INSTINCTS_UPTIME,
		FRENZIED_REGEN_UPTIME,
		FRENZIED_REGEN_HPS,
		FRENZIED_REGEN_AVG_SZ,

		LOTP_PROCS,
		LOTP_HPS,
		LOTP_AVG_SZ,

		PHYSICAL_DAMAGE_REDUCTION,
		MAGIC_DAMAGE_REDUCTION,

		NR_SKULL_BASHES,
		NR_INTERRUPTED_CASTS,
		NR_TARGET_CASTS,

		TOTAL_DTPS,

		MOB_WHITE_ATTACK_DTPS,
		MOB_WHITE_ATTACKS,
		P_MOB_WHITE_MISS,
		P_MOB_WHITE_DODGE,
		P_MOB_WHITE_CRIT,
		P_MOB_WHITE_HIT,
		MOB_WHITE_INTERVAL,
		MOB_WHITE_AVG_DMG,

		MOB_YELLOW_ATTACK_DTPS,
		MOB_YELLOW_ATTACKS,
		P_MOB_YELLOW_MISS,
		P_MOB_YELLOW_DODGE,
		P_MOB_YELLOW_HIT,
		MOB_YELLOW_INTERVAL,
		MOB_YELLOW_AVG_DMG,

		MOB_MAGIC_ATTACK_DTPS,
		MOB_MAGIC_ATTACKS,
		P_MOB_MAGIC_MISS,
		P_MOB_MAGIC_HIT,
		MOB_MAGIC_INTERVAL,
		MOB_MAGIC_AVG_DMG,

		HEROISM_UPTIME,
		UNHOLY_FRENZY_UPTIME,
		TOTT_UPTIME,
		SHATTERING_THROW_UPTIME,

		VENGEANCE_CAP,
		VENGEANCE_AVG,
		KOTJ_ENRAGE_UPTIME,
		STAMPEDE_UPTIME,

		P_RAGE_TPS,
		P_WHITE_ATTACK_TPS,
		P_FURY_SWIPES_TPS,
		P_FERAL_FF_TPS,
		P_MANGLE_TPS,
		P_MAUL_TPS,
		P_LACERATE_TPS,
		P_PULVERIZE_TPS,
		P_THRASH_TPS,
		P_SWIPE_TPS,
		P_FIERY_CLAWS_TPS,
		P_OTHER_TPS,

		RAGE_GAIN_TPS,
		RAGE_GAINED,
		RAGE_GAINED_AUTO_ATTACK,
		RAGE_GAINED_NATURAL_REACTION,
		RAGE_GAINED_PRIMAL_FURY,
		RAGE_GAINED_PRIMAL_MADNESS,
		RAGE_GAINED_ENRAGE,
		RAGE_GAINED_MOB_WHITE,
		RAGE_GAINED_MOB_YELLOW,
		RAGE_GAINED_MOB_MAGIC,
		RAGE_SPENT,
		RAGE_OVERFLOW,
		OOC_PROCS,
		OOC_AVG_RAGE_RETURN,

		WHITE_ATTACK_TPS,
		WHITE_ATTACK_DPS,
		WHITE_ATTACKS,
		P_WHITE_ATTACK_MISS,
		P_WHITE_ATTACK_DODGE,
		P_WHITE_ATTACK_PARRY,
		P_WHITE_ATTACK_GLANCE,
		P_WHITE_ATTACK_CRIT,
		P_WHITE_ATTACK_HIT,
		WHITE_ATTACK_INTERVAL,
		WHITE_ATTACK_AVG_DMG,

		FURY_SWIPES_TPS,
		FURY_SWIPES_DPS,
		FURY_SWIPES,
		P_FURY_SWIPES_MISS,
		P_FURY_SWIPES_DODGE,
		P_FURY_SWIPES_PARRY,
		P_FURY_SWIPES_CRIT,
		P_FURY_SWIPES_HIT,
		FURY_SWIPES_AVG_DMG,

		FERAL_FF_TPS,
		FERAL_FF_DPS,
		FERAL_FFS,
		P_FERAL_FF_MISS,
		P_FERAL_FF_CRIT,
		P_FERAL_FF_HIT,
		FERAL_FF_AVG_DMG,
		FERAL_FF_AVG_THREAT,
		FERAL_FF_UPTIME,

		MANGLE_TPS,
		MANGLE_DPS,
		MANGLE_TPR,
		MANGLES,
		P_MANGLE_MISS,
		P_MANGLE_DODGE,
		P_MANGLE_PARRY,
		P_MANGLE_CRIT,
		P_MANGLE_HIT,
		MANGLE_AVG_DMG,
		MANGLE_AVG_THREAT,
		MANGLE_UPTIME,

		BERSERKS,
		BERSERK_UPTIME,
		BERSERK_MANGLES,
		BERSERK_PROCS,
		BERSERK_PROC_MANGLES,
		BERSERK_PROCS_WASTED,

		LACERATE_TPS,
		LACERATE_DPS,
		LACERATE_DIRECT_TPS,
		LACERATE_DIRECT_DPS,
		LACERATE_TPR,
		LACERATES,
		P_LACERATE_MISS,
		P_LACERATE_DODGE,
		P_LACERATE_PARRY,
		P_LACERATE_CRIT,
		P_LACERATE_HIT,
		LACERATE_AVG_DMG,
		LACERATE_AVG_THREAT,
		LACERATE_DOT_DPS,
		LACERATE_DOT_TPS,
		LACERATE_TICKS,
		P_LACERATE_DOT_CRIT,
		P_LACERATE_DOT_HIT,
		LACERATE_DOT_AVG_DMG,
		LACERATE_DOT_AVG_THREAT,
		LACERATE_UPTIME,

		PULVERIZE_TPS,
		PULVERIZE_DPS,
		PULVERIZE_TPR,
		PULVERIZES,
		P_PULVERIZE_MISS,
		P_PULVERIZE_DODGE,
		P_PULVERIZE_PARRY,
		P_PULVERIZE_CRIT,
		P_PULVERIZE_HIT,
		PULVERIZE_AVG_DMG,
		PULVERIZE_AVG_THREAT,
		PULVERIZE_UPTIME,

		MAUL_TPS,
		MAUL_DPS,
		MAUL_TPR,
		MAULS,
		P_MAUL_MISS,
		P_MAUL_DODGE,
		P_MAUL_PARRY,
		P_MAUL_CRIT,
		P_MAUL_HIT,
		MAUL_AVG_DMG,
		MAUL_AVG_THREAT,

		SWIPE_TPS,
		SWIPE_DPS,
		SWIPE_TPR,
		SWIPES,
		P_SWIPE_MISS,
		P_SWIPE_DODGE,
		P_SWIPE_PARRY,
		P_SWIPE_CRIT,
		P_SWIPE_HIT,
		SWIPE_AVG_DMG,
		SWIPE_AVG_THREAT,

		THRASH_TPS,
		THRASH_DPS,
		THRASH_DIRECT_TPS,
		THRASH_DIRECT_DPS,
		THRASH_TPR,
		THRASHS,
		P_THRASH_MISS,
		P_THRASH_DODGE,
		P_THRASH_PARRY,
		P_THRASH_CRIT,
		P_THRASH_HIT,
		THRASH_AVG_DMG,
		THRASH_AVG_THREAT,
		THRASH_DOT_DPS,
		THRASH_DOT_TPS,
		THRASH_TICKS,
		P_THRASH_DOT_CRIT,
		P_THRASH_DOT_HIT,
		THRASH_DOT_AVG_DMG,
		THRASH_DOT_AVG_THREAT,
		THRASH_UPTIME,

		FIERY_CLAWS_TPS,
		FIERY_CLAWS_DPS,
		FIERY_CLAWS_TICKS,
		FIERY_CLAWS_AVG_DMG,
		FIERY_CLAWS_AVG_THREAT,
		FIERY_CLAWS_ROLLED,
		FIERY_CLAWS_ROLLED_DMG,
		FIERY_CLAWS_MUNCHED,
		FIERY_CLAWS_MUNCHED_DMG,
		FIERY_CLAWS_REFRESH_LOST,
		FIERY_CLAWS_REFRESH_LOST_DMG,

		OTHER_TPS,
		OTHER_DPS,
	}

	boolean mDumpVengeance = false;
	boolean mDumpWhiteDamage = false;
	boolean mDumpYellowDamage = false;
	boolean mDumpMagicDamage = false;
	boolean mShouldReportMitigation = false;

	// Any of these being set is either a sign that the user should buy a lottery ticket or stop being a retard.  Usually the latter.
	boolean mHasValidInfectedWoundsUptime = true;
	boolean mHasValidMobWhiteDamage = true;
	boolean mHasValidMobYellowDamage = true;
	boolean mHasValidMobMagicDamage = true;
	boolean mHasValidRageOverflow = true;

	Map<ProcEffect, Double> mProcUptimes;	// Proc uptimes

	String mConfig;
	double[] mVengeanceSamples;				// Vengeance
	double[] mWhiteDamageSamples;			// White Damage Taken
	double[] mYellowDamageSamples;			// Yellow Damage Taken
	double[] mMagicDamageSamples;			// Magic Damage Taken

	List<double[]> mVengeanceSampleList;
	List<double[]> mWhiteDamageSampleList;
	List<double[]> mYellowDamageSampleList;
	List<double[]> mMagicDamageSampleList;

	@Override
	public Report accumulate(Report r) {
		super.accumulate(r);

		BearThreatReport br = (BearThreatReport) r;

		if (br.mShouldReportMitigation == true) mShouldReportMitigation = true;
		if (br.mHasValidInfectedWoundsUptime == false) mHasValidInfectedWoundsUptime = false;
		if (br.mHasValidMobWhiteDamage == false) mHasValidMobWhiteDamage = false;
		if (br.mHasValidMobYellowDamage == false) mHasValidMobYellowDamage = false;
		if (br.mHasValidMobMagicDamage == false) mHasValidMobMagicDamage = false;
		if (br.mHasValidRageOverflow == false) mHasValidRageOverflow = false;

		if (mProcUptimes == null) {
			// XXX: Should I copy this?
			mProcUptimes = br.mProcUptimes;
		} else {
			if (br.mProcUptimes != null && br.mProcUptimes.isEmpty() == false) {
				for (Map.Entry<ProcEffect, Double> entry : br.mProcUptimes.entrySet()) {
					ProcEffect proc = entry.getKey();
					Double newUptime = entry.getValue();
					Double oldUptime = mProcUptimes.get(proc);

					mProcUptimes.put(proc, (oldUptime + newUptime));
				}
			}
		}

		if (mDumpVengeance) {
			if (mVengeanceSampleList == null) {
				mConfig = br.mConfig;
				mVengeanceSampleList = new LinkedList<double[]>();
			}
			mVengeanceSampleList.add(br.mVengeanceSamples);
		}

		if (mDumpWhiteDamage) {
			if (br.mWhiteDamageSamples == null) mDumpWhiteDamage = false;
			if (mWhiteDamageSampleList == null) {
				mConfig = br.mConfig;
				mWhiteDamageSampleList = new LinkedList<double[]>();
			}
			mWhiteDamageSampleList.add(br.mWhiteDamageSamples);
		}

		if (mDumpYellowDamage) {
			if (br.mYellowDamageSamples == null) mDumpYellowDamage = false;
			if (mYellowDamageSampleList == null) {
				mConfig = br.mConfig;
				mYellowDamageSampleList = new LinkedList<double[]>();
			}
			mYellowDamageSampleList.add(br.mYellowDamageSamples);
		}

		if (mDumpMagicDamage) {
			if (br.mMagicDamageSamples == null) mDumpMagicDamage = false;
			if (mMagicDamageSampleList == null) {
				mConfig = br.mConfig;
				mMagicDamageSampleList = new LinkedList<double[]>();
			}
			mMagicDamageSampleList.add(br.mMagicDamageSamples);
		}

		return this;
	}

	public String toString() {
		StringBuilder tmp = new StringBuilder();

		int iterations = getIterations();

		Result res;

		if (mShouldReportMitigation) {
			res = getResult(Stat.MITIGATION_VALUE);
			tmp.append("Mitigation Value: ").append(round(res.getMean())).append(" +/- ").append(round(res.getStandardError() * 1.96)).append('\n');
			tmp.append('\n');
		}

		res = getResult(Stat.THREAT_PER_SECOND);
		tmp.append("TPS: ").append(round(res.getMean())).append(" +/- ").append(round(res.getStandardError() * 1.96)).append('\n');
		tmp.append("StdDev: ").append(round(res.getStandardDeviation())).append('\n');
		tmp.append("DPS: ").append(round(getResult(Stat.DAMAGE_DEALT_PER_SECOND).getMean())).append('\n');
		tmp.append('\n');

		// XXX: These are only really useful for debugging.
//		tmp.append("TotalDamage:").append(getResult(BearThreatStat.TOTAL_DAMAGE).toString()).append('\n');
//		tmp.append("Total Damage Taken:").append(getResult(BearThreatStat.TOTAL_DAMAGE_TAKEN).toString()).append('\n');
//		tmp.append("Total Damage Base:").append(getResult(BearThreatStat.TOTAL_DAMAGE_BASE).toString()).append('\n');
//		tmp.append('\n');

		// Mitigation/Survivability
		tmp.append("Survivability Stats:").append('\n');
		tmp.append(" Demoralizing Roar uptime: ").append(round(getResult(BearThreatStat.DEMORALIZING_ROAR_UPTIME).getMean())).append('%').append('\n');
		if (mHasValidInfectedWoundsUptime) {
			tmp.append(" Infected Wounds uptime: ").append(round(getResult(BearThreatStat.INFECTED_WOUNDS_UPTIME).getMean())).append('%').append('\n');
		} else {
			tmp.append(" Infected Wounds uptime: ").append("Your spec is bad and you should feel bad!").append('\n');
		}
		tmp.append(" Savage Defense uptime: ").append(round(getResult(BearThreatStat.SAVAGE_DEFENSE_UPTIME).getMean())).append('%').append('\n');
		tmp.append("  Damage absorbed: ").append(round(getResult(BearThreatStat.SAVAGE_DEFENSE_ABSORBED).getMean())).append('\n');
		tmp.append("  Average shield: ").append(round(getResult(BearThreatStat.SAVAGE_DEFENSE_AVG_SZ).getMean())).append('\n');
		tmp.append("  Procs: ").append(round(getResult(BearThreatStat.SAVAGE_DEFENSE_PROCS).getMean())).append('\n');
		tmp.append("  Proc interval: ").append(round(getResult(BearThreatStat.SAVAGE_DEFENSE_PROC_INTERVAL).getMean())).append(" sec").append('\n');
		if (getResult(BearThreatStat.BARKSKIN_UPTIME).getMax() > 0) {
			tmp.append(" Barkskin uptime: ").append(round(getResult(BearThreatStat.BARKSKIN_UPTIME).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.TIER_12_4PC_UPTIME).getMax() > 0) {
			tmp.append(" 4T12 uptime: ").append(round(getResult(BearThreatStat.TIER_12_4PC_UPTIME).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.SURVIVAL_INSTINCTS_UPTIME).getMax() > 0) {
			tmp.append(" Survival Instincts uptime: ").append(round(getResult(BearThreatStat.SURVIVAL_INSTINCTS_UPTIME).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.FRENZIED_REGEN_UPTIME).getMax() > 0) {
			tmp.append(" Frenzied Regeneration uptime: ").append(round(getResult(BearThreatStat.FRENZIED_REGEN_UPTIME).getMean())).append('%').append('\n');
			if (getResult(BearThreatStat.FRENZIED_REGEN_HPS).getMax() > 0) {
				tmp.append("  HPS: ").append(round(getResult(BearThreatStat.FRENZIED_REGEN_HPS).getMean())).append('\n');
				tmp.append("  Average heal: ").append(round(getResult(BearThreatStat.FRENZIED_REGEN_AVG_SZ).getMean())).append('\n');
			}
		}
		if (getResult(BearThreatStat.LOTP_HPS).getMax() > 0) {
			tmp.append(" Leader of the Pack HPS: ").append(round(getResult(BearThreatStat.LOTP_HPS).getMean())).append('\n');
			tmp.append("  Average heal: ").append(round(getResult(BearThreatStat.LOTP_AVG_SZ).getMean())).append('\n');
			tmp.append("  Procs: ").append(round(getResult(BearThreatStat.LOTP_PROCS).getMean())).append('\n');
		}
		if (getResult(BearThreatStat.TOTAL_DTPS).getMax() > 0) {
			if (getResult(BearThreatStat.MOB_WHITE_ATTACK_DTPS).getMax() > 0 || getResult(BearThreatStat.MOB_YELLOW_ATTACK_DTPS).getMax() > 0) {
				tmp.append(" Physical damage reduction: ").append(round(getResult(BearThreatStat.PHYSICAL_DAMAGE_REDUCTION).getMean())).append('%').append('\n');
			}
			if (getResult(BearThreatStat.MOB_MAGIC_ATTACK_DTPS).getMax() > 0) {
				tmp.append(" Magic damage reduction: ").append(round(getResult(BearThreatStat.MAGIC_DAMAGE_REDUCTION).getMean())).append('%').append('\n');
			}
		}
		tmp.append('\n');

		// Incoming Damage
		if (getResult(BearThreatStat.TOTAL_DTPS).getMax() > 0) {
			tmp.append("Incoming Damage").append('\n');
			tmp.append(" DTPS: ").append(round(getResult(BearThreatStat.TOTAL_DTPS).getMean())).append('\n');
			if (getResult(BearThreatStat.MOB_WHITE_ATTACK_DTPS).getMax() > 0 && mHasValidMobWhiteDamage) {
				tmp.append(" White Attack: ").append('\n');
				tmp.append("  DTPS: ").append(round(getResult(BearThreatStat.MOB_WHITE_ATTACK_DTPS).getMean())).append('\n');
				tmp.append("  Nr. White Attacks: ").append(round(getResult(BearThreatStat.MOB_WHITE_ATTACKS).getMean())).append('\n');
				tmp.append("  Miss/Dodge/Crit/Hit: ").
					append(round(getResult(BearThreatStat.P_MOB_WHITE_MISS).getMean())).append('%').append('/').
					append(round(getResult(BearThreatStat.P_MOB_WHITE_DODGE).getMean())).append('%').append('/').
					append(round(getResult(BearThreatStat.P_MOB_WHITE_CRIT).getMean())).append('%').append('/').
					append(round(getResult(BearThreatStat.P_MOB_WHITE_HIT).getMean())).append('%').append('\n');
				tmp.append("  Interval: ").append(round(getResult(BearThreatStat.MOB_WHITE_INTERVAL).getMean())).append(" sec").append('\n');
				tmp.append("  Average damage: ").append(round(getResult(BearThreatStat.MOB_WHITE_AVG_DMG).getMean())).append('\n');
			}
			if (getResult(BearThreatStat.MOB_YELLOW_ATTACK_DTPS).getMax() > 0 && mHasValidMobYellowDamage) {
				tmp.append(" Yellow Attack: ").append('\n');
				tmp.append("  DTPS: ").append(round(getResult(BearThreatStat.MOB_YELLOW_ATTACK_DTPS).getMean())).append('\n');
				tmp.append("  Nr. Yellow Attacks: ").append(round(getResult(BearThreatStat.MOB_YELLOW_ATTACKS).getMean())).append('\n');
				tmp.append("  Miss/Dodge/Hit: ").
					append(round(getResult(BearThreatStat.P_MOB_YELLOW_MISS).getMean())).append('%').append('/').
					append(round(getResult(BearThreatStat.P_MOB_YELLOW_DODGE).getMean())).append('%').append('/').
					append(round(getResult(BearThreatStat.P_MOB_YELLOW_HIT).getMean())).append('%').append('\n');
				tmp.append("  Interval: ").append(round(getResult(BearThreatStat.MOB_YELLOW_INTERVAL).getMean())).append(" sec").append('\n');
				tmp.append("  Average damage: ").append(round(getResult(BearThreatStat.MOB_YELLOW_AVG_DMG).getMean())).append('\n');
			}
			if (getResult(BearThreatStat.MOB_MAGIC_ATTACK_DTPS).getMax() > 0 && mHasValidMobMagicDamage) {
				tmp.append(" Magic Attack: ").append('\n');
				tmp.append("  DTPS: ").append(round(getResult(BearThreatStat.MOB_MAGIC_ATTACK_DTPS).getMean())).append('\n');
				tmp.append("  Nr. Magic Attacks: ").append(round(getResult(BearThreatStat.MOB_MAGIC_ATTACKS).getMean())).append('\n');
				tmp.append("  Miss/Hit: ").
					append(round(getResult(BearThreatStat.P_MOB_MAGIC_MISS).getMean())).append('%').append('/').
					append(round(getResult(BearThreatStat.P_MOB_MAGIC_HIT).getMean())).append('%').append('\n');
				tmp.append("  Interval: ").append(round(getResult(BearThreatStat.MOB_MAGIC_INTERVAL).getMean())).append(" sec").append('\n');
				tmp.append("  Average damage: ").append(round(getResult(BearThreatStat.MOB_MAGIC_AVG_DMG).getMean())).append('\n');
			}
			tmp.append('\n');
		}

		// Skull Bash
		if (getResult(BearThreatStat.NR_TARGET_CASTS).getMax() > 0) {
			tmp.append("Interrupt Stats:").append('\n');
			tmp.append(" Interuptable casts: ").append(round(getResult(BearThreatStat.NR_TARGET_CASTS).getMean())).append('\n');
			tmp.append(" Nr. Skull Bashs: ").append(round(getResult(BearThreatStat.NR_SKULL_BASHES).getMean())).append('\n');
			tmp.append(" Interrupted casts: ").append(round(getResult(BearThreatStat.NR_INTERRUPTED_CASTS).getMean())).append('\n');
			tmp.append('\n');
		}

		// Threat Boosts
		tmp.append("Threat Boosts:").append('\n');
		tmp.append(" Vengeance:").append('\n');
		tmp.append("  Vengeance cap: ").append(round(getResult(BearThreatStat.VENGEANCE_CAP).getMean())).append('\n');
		tmp.append("  Vengeance AP: ").append(round(getResult(BearThreatStat.VENGEANCE_AVG).getMean())).append('\n');
		if (getResult(BearThreatStat.KOTJ_ENRAGE_UPTIME).getMax() > 0) {
			tmp.append(" King of the Jungle uptime: ").append(round(getResult(BearThreatStat.KOTJ_ENRAGE_UPTIME).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.STAMPEDE_UPTIME).getMax() > 0) {
			tmp.append(" Stampede uptime: ").append(round(getResult(BearThreatStat.STAMPEDE_UPTIME).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.HEROISM_UPTIME).getMax() > 0) {
			tmp.append(" Heroism uptime: ").append(round(getResult(BearThreatStat.HEROISM_UPTIME).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.TOTT_UPTIME).getMax() > 0) {
			tmp.append(" Tricks of the Trade uptime: ").append(round(getResult(BearThreatStat.TOTT_UPTIME).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.UNHOLY_FRENZY_UPTIME).getMax() > 0) {
			tmp.append(" Unholy Frenzy uptime: ").append(round(getResult(BearThreatStat.UNHOLY_FRENZY_UPTIME).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.SHATTERING_THROW_UPTIME).getMax() > 0) {
			tmp.append(" Shattering Throw uptime: ").append(round(getResult(BearThreatStat.SHATTERING_THROW_UPTIME).getMean())).append('%').append('\n');
		}
		tmp.append('\n');

		// Ability Overview
		tmp.append("Ability Overview:").append('\n');
		if (getResult(BearThreatStat.P_RAGE_TPS).getMax() > 0) {
			tmp.append(" Rage gain threat: ").append(round(getResult(BearThreatStat.P_RAGE_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_WHITE_ATTACK_TPS).getMax() > 0) {
			tmp.append(" White Attack threat: ").append(round(getResult(BearThreatStat.P_WHITE_ATTACK_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_FURY_SWIPES_TPS).getMax() > 0) {
			tmp.append(" Fury Swipes threat: ").append(round(getResult(BearThreatStat.P_FURY_SWIPES_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_FERAL_FF_TPS).getMax() > 0) {
			tmp.append(" Feral Faerie Fire threat: ").append(round(getResult(BearThreatStat.P_FERAL_FF_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_MANGLE_TPS).getMax() > 0) {
			tmp.append(" Mangle threat: ").append(round(getResult(BearThreatStat.P_MANGLE_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_LACERATE_TPS).getMax() > 0) {
			tmp.append(" Lacerate threat: ").append(round(getResult(BearThreatStat.P_LACERATE_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_PULVERIZE_TPS).getMax() > 0) {
			tmp.append(" Pulverize threat: ").append(round(getResult(BearThreatStat.P_PULVERIZE_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_MAUL_TPS).getMax() > 0) {
			tmp.append(" Maul threat: ").append(round(getResult(BearThreatStat.P_MAUL_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_SWIPE_TPS).getMax() > 0) {
			tmp.append(" Swipe threat: ").append(round(getResult(BearThreatStat.P_SWIPE_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_THRASH_TPS).getMax() > 0) {
			tmp.append(" Thrash threat: ").append(round(getResult(BearThreatStat.P_THRASH_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_FIERY_CLAWS_TPS).getMax() > 0) {
			tmp.append(" Fiery Claws threat: ").append(round(getResult(BearThreatStat.P_FIERY_CLAWS_TPS).getMean())).append('%').append('\n');
		}
		if (getResult(BearThreatStat.P_OTHER_TPS).getMax() > 0) {
			tmp.append(" Other threat: ").append(round(getResult(BearThreatStat.P_OTHER_TPS).getMean())).append('%').append('\n');
		}
		tmp.append('\n');

		// Rage
		// Note: Technically speaking all of the rage sources are optional, but only the king of retards would skip the ones I display.
		tmp.append("Rage:").append('\n');
		tmp.append(" TPS: ").append(round(getResult(BearThreatStat.RAGE_GAIN_TPS).getMean())).append('\n');
		tmp.append(" Rage gained: ").append(round(getResult(BearThreatStat.RAGE_GAINED).getMean())).append('\n');
		tmp.append("  Auto attack: ").append(round(getResult(BearThreatStat.RAGE_GAINED_AUTO_ATTACK).getMean())).append('\n');
		tmp.append("  Natural Reaction: ").append(round(getResult(BearThreatStat.RAGE_GAINED_NATURAL_REACTION).getMean())).append('\n');
		tmp.append("  Primal Fury: ").append(round(getResult(BearThreatStat.RAGE_GAINED_PRIMAL_FURY).getMean())).append('\n');
		if (getResult(BearThreatStat.RAGE_GAINED_PRIMAL_MADNESS).getMax() > 0) {
			tmp.append("  Primal Madness: ").append(round(getResult(BearThreatStat.RAGE_GAINED_PRIMAL_MADNESS).getMean())).append('\n');
		}
		tmp.append("  Enrage: ").append(round(getResult(BearThreatStat.RAGE_GAINED_ENRAGE).getMean())).append('\n');
		if (getResult(BearThreatStat.RAGE_GAINED_MOB_WHITE).getMax() > 0) {
			tmp.append("  Mob Melee: ").append(round(getResult(BearThreatStat.RAGE_GAINED_MOB_WHITE).getMean())).append('\n');
		}
		if (getResult(BearThreatStat.RAGE_GAINED_MOB_YELLOW).getMax() > 0) {
			tmp.append("  Mob Yellow: ").append(round(getResult(BearThreatStat.RAGE_GAINED_MOB_YELLOW).getMean())).append('\n');
		}
		if (getResult(BearThreatStat.RAGE_GAINED_MOB_MAGIC).getMax() > 0) {
			tmp.append("  Mob Magic: ").append(round(getResult(BearThreatStat.RAGE_GAINED_MOB_MAGIC).getMean())).append('\n');
		}
		tmp.append(" Rage spent: ").append(round(getResult(BearThreatStat.RAGE_SPENT).getMean())).append('\n');
		if (getResult(BearThreatStat.RAGE_OVERFLOW).getMax() > 0 && mHasValidRageOverflow) {
			tmp.append(" Rage Overflow: ").append(round(getResult(BearThreatStat.RAGE_OVERFLOW).getMean())).append('\n');
		}
		tmp.append(" OoC Procs: ").append(round(getResult(BearThreatStat.OOC_PROCS).getMean())).append('\n');
		tmp.append("  Average Rage return: ").append(round(getResult(BearThreatStat.OOC_AVG_RAGE_RETURN).getMean())).append('\n');
		tmp.append('\n');

		// White Attack
		tmp.append("White Attack:").append('\n');
		tmp.append(" TPS: ").append(round(getResult(BearThreatStat.WHITE_ATTACK_TPS).getMean())).append('\n');
		tmp.append(" DPS: ").append(round(getResult(BearThreatStat.WHITE_ATTACK_DPS).getMean())).append('\n');
		tmp.append(" Nr. White Attacks: ").append(round(getResult(BearThreatStat.WHITE_ATTACKS).getMean())).append('\n');
		tmp.append(" Miss/Dodge/Parry/Glance/Crit/Hit: ").
			append(round(getResult(BearThreatStat.P_WHITE_ATTACK_MISS).getMean())).append('%').append('/').
			append(round(getResult(BearThreatStat.P_WHITE_ATTACK_DODGE).getMean())).append('%').append('/').
			append(round(getResult(BearThreatStat.P_WHITE_ATTACK_PARRY).getMean())).append('%').append('/').
			append(round(getResult(BearThreatStat.P_WHITE_ATTACK_GLANCE).getMean())).append('%').append('/').
			append(round(getResult(BearThreatStat.P_WHITE_ATTACK_CRIT).getMean())).append('%').append('/').
			append(round(getResult(BearThreatStat.P_WHITE_ATTACK_HIT).getMean())).append('%').append('\n');
		tmp.append(" Interval: ").append(round(getResult(BearThreatStat.WHITE_ATTACK_INTERVAL).getMean())).append(" sec").append('\n');
		tmp.append(" Average damage: ").append(round(getResult(BearThreatStat.WHITE_ATTACK_AVG_DMG).getMean())).append('\n');
		tmp.append('\n');

		// Fury Swipes
		if (getResult(BearThreatStat.FURY_SWIPES_TPS).getMax() > 0) {
			tmp.append("Fury Swipes:").append('\n');
			tmp.append(" TPS: ").append(round(getResult(BearThreatStat.FURY_SWIPES_TPS).getMean())).append('\n');
			tmp.append(" DPS: ").append(round(getResult(BearThreatStat.FURY_SWIPES_DPS).getMean())).append('\n');
			tmp.append(" Nr. Fury Swipes: ").append(round(getResult(BearThreatStat.FURY_SWIPES).getMean())).append('\n');
			tmp.append(" Miss/Dodge/Parry/Crit/Hit: ").
				append(round(getResult(BearThreatStat.P_FURY_SWIPES_MISS).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_FURY_SWIPES_DODGE).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_FURY_SWIPES_PARRY).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_FURY_SWIPES_CRIT).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_FURY_SWIPES_HIT).getMean())).append('%').append('\n');
			tmp.append(" Average damage: ").append(round(getResult(BearThreatStat.FURY_SWIPES_AVG_DMG).getMean())).append('\n');
			tmp.append('\n');
		}

		// Feral FF
		if (getResult(BearThreatStat.FERAL_FF_TPS).getMax() > 0) {
			tmp.append("Feral Faerie Fire:").append('\n');
			tmp.append(" TPS: ").append(round(getResult(BearThreatStat.FERAL_FF_TPS).getMean())).append('\n');
			tmp.append(" DPS: ").append(round(getResult(BearThreatStat.FERAL_FF_DPS).getMean())).append('\n');
			tmp.append(" Nr. Faerie Fires: ").append(round(getResult(BearThreatStat.FERAL_FFS).getMean())).append('\n');
			tmp.append(" Miss/Crit/Hit: ").
				append(round(getResult(BearThreatStat.P_FERAL_FF_MISS).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_FERAL_FF_CRIT).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_FERAL_FF_HIT).getMean())).append('%').append('\n');
			tmp.append(" Average damage: ").append(round(getResult(BearThreatStat.FERAL_FF_AVG_DMG).getMean())).append('\n');
			tmp.append(" Average threat: ").append(round(getResult(BearThreatStat.FERAL_FF_AVG_THREAT).getMean())).append('\n');
			tmp.append(" Uptime: ").append(round(getResult(BearThreatStat.FERAL_FF_UPTIME).getMean())).append('%').append('\n');
			tmp.append('\n');
		}

		// Mangle
		// Note: Technically I could report Berserk metrics even if the use didn't Mangle, but what's the point?
		if (getResult(BearThreatStat.MANGLE_TPS).getMax() > 0) {
			tmp.append("Mangle:").append('\n');
			tmp.append(" TPS: ").append(round(getResult(BearThreatStat.MANGLE_TPS).getMean())).append('\n');
			tmp.append(" DPS: ").append(round(getResult(BearThreatStat.MANGLE_DPS).getMean())).append('\n');
			tmp.append(" TPR: ").append(round(getResult(BearThreatStat.MANGLE_TPR).getMean())).append('\n');
			tmp.append(" Nr. Mangles: ").append(round(getResult(BearThreatStat.MANGLES).getMean())).append('\n');
			tmp.append(" Miss/Dodge/Parry/Crit/Hit: ").
				append(round(getResult(BearThreatStat.P_MANGLE_MISS).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_MANGLE_DODGE).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_MANGLE_PARRY).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_MANGLE_CRIT).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_MANGLE_HIT).getMean())).append('%').append('\n');
			tmp.append(" Average damage: ").append(round(getResult(BearThreatStat.MANGLE_AVG_DMG).getMean())).append('\n');
			tmp.append(" Average threat: ").append(round(getResult(BearThreatStat.MANGLE_AVG_THREAT).getMean())).append('\n');
			tmp.append(" Uptime: ").append(round(getResult(BearThreatStat.MANGLE_UPTIME).getMean())).append('%').append('\n');
			if (getResult(BearThreatStat.BERSERKS).getMax() > 0) {
				tmp.append(" Berserk:").append('\n');
				tmp.append("  Nr. Berserks: ").append(round(getResult(BearThreatStat.BERSERKS).getMean())).append('\n');
				tmp.append("  Uptime: ").append(round(getResult(BearThreatStat.BERSERK_UPTIME).getMean())).append('%').append('\n');
				tmp.append("  Nr. Mangles: ").append(round(getResult(BearThreatStat.BERSERK_MANGLES).getMean())).append('\n');
			}
			if (getResult(BearThreatStat.BERSERK_PROCS).getMax() > 0) {
				tmp.append(" Berserk Proc:").append('\n');
				tmp.append("  Nr. Berserk Procs: ").append(round(getResult(BearThreatStat.BERSERK_PROCS).getMean())).append('\n');
				tmp.append("  Nr. Mangles: ").append(round(getResult(BearThreatStat.BERSERK_PROC_MANGLES).getMean())).append('\n');
				tmp.append("  Nr. Procs wasted: ").append(round(getResult(BearThreatStat.BERSERK_PROCS_WASTED).getMean())).append('\n');
			}
			tmp.append('\n');
		}

		// Lacerate
		if (getResult(BearThreatStat.LACERATE_TPS).getMax() > 0) {
			tmp.append("Lacerate:").append('\n');
			tmp.append(" TPS: ").append(round(getResult(BearThreatStat.LACERATE_TPS).getMean())).append('\n');
			tmp.append(" DPS: ").append(round(getResult(BearThreatStat.LACERATE_DPS).getMean())).append('\n');
			tmp.append(" Direct Damage:").append('\n');
			tmp.append("  TPS: ").append(round(getResult(BearThreatStat.LACERATE_DIRECT_TPS).getMean())).append('\n');
			tmp.append("  DPS: ").append(round(getResult(BearThreatStat.LACERATE_DIRECT_DPS).getMean())).append('\n');
			tmp.append("  TPR: ").append(round(getResult(BearThreatStat.LACERATE_TPR).getMean())).append('\n');
			tmp.append("  Nr. Lacerates: ").append(round(getResult(BearThreatStat.LACERATES).getMean())).append('\n');
			tmp.append("  Miss/Dodge/Parry/Crit/Hit: ").
				append(round(getResult(BearThreatStat.P_LACERATE_MISS).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_LACERATE_DODGE).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_LACERATE_PARRY).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_LACERATE_CRIT).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_LACERATE_HIT).getMean())).append('%').append('\n');
			tmp.append("  Average damage: ").append(round(getResult(BearThreatStat.LACERATE_AVG_DMG).getMean())).append('\n');
			tmp.append("  Average threat: ").append(round(getResult(BearThreatStat.LACERATE_AVG_THREAT).getMean())).append('\n');
			tmp.append(" DoT:").append('\n');
			tmp.append("  TPS: ").append(round(getResult(BearThreatStat.LACERATE_DOT_TPS).getMean())).append('\n');
			tmp.append("  DPS: ").append(round(getResult(BearThreatStat.LACERATE_DOT_DPS).getMean())).append('\n');
			tmp.append("  Nr. ticks: ").append(round(getResult(BearThreatStat.LACERATE_TICKS).getMean())).append('\n');
			tmp.append("  Crit/Hit: ").
				append(round(getResult(BearThreatStat.P_LACERATE_DOT_CRIT).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_LACERATE_DOT_HIT).getMean())).append('%').append('\n');
			tmp.append("  Average damage: ").append(round(getResult(BearThreatStat.LACERATE_DOT_AVG_DMG).getMean())).append('\n');
			tmp.append("  Average threat: ").append(round(getResult(BearThreatStat.LACERATE_DOT_AVG_THREAT).getMean())).append('\n');
			tmp.append(" Uptime: ").append(round(getResult(BearThreatStat.LACERATE_UPTIME).getMean())).append('%').append('\n');
			tmp.append('\n');
		}

		// Pulverize
		if (getResult(BearThreatStat.PULVERIZE_TPS).getMax() > 0) {
			tmp.append("Pulverize:").append('\n');
			tmp.append(" TPS: ").append(round(getResult(BearThreatStat.PULVERIZE_TPS).getMean())).append('\n');
			tmp.append(" DPS: ").append(round(getResult(BearThreatStat.PULVERIZE_DPS).getMean())).append('\n');
			tmp.append(" TPR: ").append(round(getResult(BearThreatStat.PULVERIZE_TPR).getMean())).append('\n');
			tmp.append(" Nr. Pulverizes: ").append(round(getResult(BearThreatStat.PULVERIZES).getMean())).append('\n');
			tmp.append(" Miss/Dodge/Parry/Crit/Hit: ").
				append(round(getResult(BearThreatStat.P_PULVERIZE_MISS).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_PULVERIZE_DODGE).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_PULVERIZE_PARRY).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_PULVERIZE_CRIT).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_PULVERIZE_HIT).getMean())).append('%').append('\n');
			tmp.append(" Average damage: ").append(round(getResult(BearThreatStat.PULVERIZE_AVG_DMG).getMean())).append('\n');
			tmp.append(" Average threat: ").append(round(getResult(BearThreatStat.PULVERIZE_AVG_THREAT).getMean())).append('\n');
			tmp.append(" Uptime: ").append(round(getResult(BearThreatStat.PULVERIZE_UPTIME).getMean())).append('%').append('\n');
			tmp.append('\n');
		}

		// Maul
		if (getResult(BearThreatStat.MAUL_TPS).getMax() > 0) {
			tmp.append("Maul:").append('\n');
			tmp.append(" TPS: ").append(round(getResult(BearThreatStat.MAUL_TPS).getMean())).append('\n');
			tmp.append(" DPS: ").append(round(getResult(BearThreatStat.MAUL_DPS).getMean())).append('\n');
			tmp.append(" TPR: ").append(round(getResult(BearThreatStat.MAUL_TPR).getMean())).append('\n');
			tmp.append(" Nr. Mauls: ").append(round(getResult(BearThreatStat.MAULS).getMean())).append('\n');
			tmp.append(" Miss/Dodge/Parry/Crit/Hit: ").
				append(round(getResult(BearThreatStat.P_MAUL_MISS).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_MAUL_DODGE).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_MAUL_PARRY).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_MAUL_CRIT).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_MAUL_HIT).getMean())).append('%').append('\n');
			tmp.append(" Average damage: ").append(round(getResult(BearThreatStat.MAUL_AVG_DMG).getMean())).append('\n');
			tmp.append(" Average threat: ").append(round(getResult(BearThreatStat.MAUL_AVG_THREAT).getMean())).append('\n');
			tmp.append('\n');
		}

		// Swipe
		if (getResult(BearThreatStat.SWIPE_TPS).getMax() > 0) {
			tmp.append("Swipe:").append('\n');
			tmp.append(" TPS: ").append(round(getResult(BearThreatStat.SWIPE_TPS).getMean())).append('\n');
			tmp.append(" DPS: ").append(round(getResult(BearThreatStat.SWIPE_DPS).getMean())).append('\n');
			tmp.append(" TPR: ").append(round(getResult(BearThreatStat.SWIPE_TPR).getMean())).append('\n');
			tmp.append(" Nr. Swipes: ").append(round(getResult(BearThreatStat.SWIPES).getMean())).append('\n');
			tmp.append(" Miss/Dodge/Parry/Crit/Hit: ").
				append(round(getResult(BearThreatStat.P_SWIPE_MISS).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_SWIPE_DODGE).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_SWIPE_PARRY).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_SWIPE_CRIT).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_SWIPE_HIT).getMean())).append('%').append('\n');
			tmp.append(" Average damage: ").append(round(getResult(BearThreatStat.SWIPE_AVG_DMG).getMean())).append('\n');
			tmp.append(" Average threat: ").append(round(getResult(BearThreatStat.SWIPE_AVG_THREAT).getMean())).append('\n');
			tmp.append('\n');
		}

		// Thrash
		if (getResult(BearThreatStat.THRASH_TPS).getMax() > 0) {
			tmp.append("Thrash:").append('\n');
			tmp.append(" TPS: ").append(round(getResult(BearThreatStat.THRASH_TPS).getMean())).append('\n');
			tmp.append(" DPS: ").append(round(getResult(BearThreatStat.THRASH_DPS).getMean())).append('\n');
			tmp.append(" Direct Damage:").append('\n');
			tmp.append("  TPS: ").append(round(getResult(BearThreatStat.THRASH_DIRECT_TPS).getMean())).append('\n');
			tmp.append("  DPS: ").append(round(getResult(BearThreatStat.THRASH_DIRECT_DPS).getMean())).append('\n');
			tmp.append("  TPR: ").append(round(getResult(BearThreatStat.THRASH_TPR).getMean())).append('\n');
			tmp.append("  Nr. Thrashs: ").append(round(getResult(BearThreatStat.THRASHS).getMean())).append('\n');
			tmp.append("  Miss/Dodge/Parry/Crit/Hit: ").
				append(round(getResult(BearThreatStat.P_THRASH_MISS).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_THRASH_DODGE).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_THRASH_PARRY).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_THRASH_CRIT).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_THRASH_HIT).getMean())).append('%').append('\n');
			tmp.append("  Average damage: ").append(round(getResult(BearThreatStat.THRASH_AVG_DMG).getMean())).append('\n');
			tmp.append("  Average threat: ").append(round(getResult(BearThreatStat.THRASH_AVG_THREAT).getMean())).append('\n');
			tmp.append(" DoT:").append('\n');
			tmp.append("  TPS: ").append(round(getResult(BearThreatStat.THRASH_DOT_TPS).getMean())).append('\n');
			tmp.append("  DPS: ").append(round(getResult(BearThreatStat.THRASH_DOT_DPS).getMean())).append('\n');
			tmp.append("  Nr. ticks: ").append(round(getResult(BearThreatStat.THRASH_TICKS).getMean())).append('\n');
			tmp.append("  Crit/Hit: ").
				append(round(getResult(BearThreatStat.P_THRASH_DOT_CRIT).getMean())).append('%').append('/').
				append(round(getResult(BearThreatStat.P_THRASH_DOT_HIT).getMean())).append('%').append('\n');
			tmp.append("  Average damage: ").append(round(getResult(BearThreatStat.THRASH_DOT_AVG_DMG).getMean())).append('\n');
			tmp.append("  Average threat: ").append(round(getResult(BearThreatStat.THRASH_DOT_AVG_THREAT).getMean())).append('\n');
			tmp.append(" Uptime: ").append(round(getResult(BearThreatStat.THRASH_UPTIME).getMean())).append('%').append('\n');
			tmp.append('\n');
		}

		// Fiery Claws (Tier 12 2 pc)
		if (getResult(BearThreatStat.FIERY_CLAWS_TPS).getMax() > 0) {
			tmp.append("Fiery Claws:").append('\n');
			tmp.append(" TPS: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_TPS).getMean())).append('\n');
			tmp.append(" DPS: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_DPS).getMean())).append('\n');
			tmp.append(" Nr. ticks: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_TICKS).getMean())).append('\n');
			if (getResult(BearThreatStat.FIERY_CLAWS_ROLLED).getMax() > 0) {
				tmp.append(" Nr. rolled: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_ROLLED).getMean())).append('\n');
				tmp.append("  Rolled damage: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_ROLLED_DMG).getMean())).append('\n');
			}
			if (getResult(BearThreatStat.FIERY_CLAWS_MUNCHED).getMax() > 0) {
				tmp.append(" Nr. munched: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_MUNCHED).getMean())).append('\n');
				tmp.append("  Munched damage: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_MUNCHED_DMG).getMean())).append('\n');
			}
			if (getResult(BearThreatStat.FIERY_CLAWS_REFRESH_LOST).getMax() > 0) {
				tmp.append(" Nr. refreshes Lost: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_REFRESH_LOST).getMean())).append('\n');
				tmp.append("  Refresh lost damage: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_REFRESH_LOST_DMG).getMean())).append('\n');
			}
			tmp.append(" Average damage: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_AVG_DMG).getMean())).append('\n');
			tmp.append(" Average threat: ").append(round(getResult(BearThreatStat.FIERY_CLAWS_AVG_THREAT).getMean())).append('\n');
			tmp.append('\n');
		}

		// Other
		if (getResult(BearThreatStat.OTHER_TPS).getMax() > 0 || getResult(BearThreatStat.OTHER_DPS).getMax() > 0) {
			tmp.append("Other Sources:").append('\n');
			tmp.append(" TPS: ").append(round(getResult(BearThreatStat.OTHER_TPS).getMean())).append('\n');
			tmp.append(" DPS: ").append(round(getResult(BearThreatStat.OTHER_DPS).getMean())).append('\n');
			tmp.append('\n');
		}

		// Trinkets/Procs
		// TODO: You know what would be cool?  If I sorted this.
		if (mProcUptimes != null && mProcUptimes.isEmpty() == false) {
			tmp.append("Trinkets/Procs:").append('\n');
			for (Map.Entry<ProcEffect, Double> entry : mProcUptimes.entrySet()) {
				ProcEffect proc = entry.getKey();
				Double uptime = entry.getValue();

				if (proc.buffDuration == 0)
					tmp.append(' ').append(proc.name).append(" procs: ").append(round(uptime / iterations)).append('\n');
				else
					tmp.append(' ').append(proc.name).append(" uptime: ").append(round(uptime / iterations * 100)).append('%').append('\n');
			}
		}

		// Dump Vengeance with the CSV dumper.
		if (mDumpVengeance) {
			mDumpVengeance = false;
			CSVDumper.dump("vengeance.csv", "Vengeance Dump:\nConfig: " + mConfig, mVengeanceSampleList);
		}

		// Dump White Damage with the CSV dumper.
		if (mDumpWhiteDamage) {
			mDumpWhiteDamage = false;
			CSVDumper.dump("whitedamage.csv", "White Damage Taken Dump:\nConfig: " + mConfig, mWhiteDamageSampleList);
		}

		// Dump Yellow Damage with the CSV dumper.
		if (mDumpYellowDamage) {
			mDumpYellowDamage = false;
			CSVDumper.dump("yellowdamage.csv", "Yellow Damage Taken Dump:\nConfig: " + mConfig, mYellowDamageSampleList);
		}

		// Dump Magic Damage with the CSV dumper.
		if (mDumpMagicDamage) {
			mDumpMagicDamage = false;
			CSVDumper.dump("magicdamage.csv", "Magic Damage Taken Dump:\nConfig: " + mConfig, mMagicDamageSampleList);
		}

		return tmp.toString();
	}
}
